#include "StdAfx.h"
#include "PhysicsHelper.h"
#include "PhysicsSystem.h"

using namespace Ogre;

void PhysicsHelper::getMeshInformation (Mesh* const mesh,
										float* &vertices,
							  unsigned int &vertex_count,
								           int* &indices,
							   unsigned int &index_count,
									     float* &normals,
							  unsigned short* &materials,
										     float* &min,
										     float* &max,
									    Vector3 position,
									   Quaternion orient,
										   Vector3 scale)
{
	bool added_shared = false;
	size_t current_offset = 0;
	size_t shared_offset = 0;
	size_t next_offset = 0;
	size_t index_offset = 0;
	vertex_count = index_count = 0;

	min = new float[3];
	min[0] = mesh->getBounds().getMinimum().x * scale.x;
	min[1] = mesh->getBounds().getMinimum().y * scale.y;
	min[2] = mesh->getBounds().getMinimum().z * scale.z;

	max = new float[3];
	max[0] = mesh->getBounds().getMaximum().x * scale.x;
	max[1] = mesh->getBounds().getMaximum().y * scale.y;
	max[2] = mesh->getBounds().getMaximum().z * scale.z;

	// Calculate how many vertices and indices we're going to need
	for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		Ogre::SubMesh* submesh = mesh->getSubMesh( i );

		// We only need to add the shared vertices once
		if(submesh->useSharedVertices)
		{
			if( !added_shared )
			{
				vertex_count += mesh->sharedVertexData->vertexCount;
				added_shared = true;
			}
		}
		else
		{
			vertex_count += submesh->vertexData->vertexCount;
		}
		// Add the indices
		index_count += submesh->indexData->indexCount;
	}


	// Allocate space for the vertices and indices
	vertex_count *= 3;
	vertices = new float[vertex_count];
	indices  = new int[index_count];
	normals  = new float[index_count/3*3];
	materials = new NxMaterialIndex[index_count/3];
	added_shared = false;

	// Run through the submeshes again, adding the data into the arrays
	int vct = 0;
	int nct = 0;
	int mct = 0;
	for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
	{
		Ogre::SubMesh* submesh = mesh->getSubMesh(i);
		Ogre::String mat_name = submesh->getMaterialName();
		printf(">>>>>> sub %i mat : %s\n", i, mat_name.c_str());
		Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
		//vertices
		if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
		{
			if(submesh->useSharedVertices)
			{
				added_shared = true;
				shared_offset = current_offset;
			}

			const Ogre::VertexElement* posElem =
			vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);

			Ogre::HardwareVertexBufferSharedPtr vbuf =
			vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());

			unsigned char* vertex =
			static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));

			float* pfloat;

			for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
			{
				posElem->baseVertexPointerToElement(vertex, &pfloat);
				Ogre::Vector3 pt(pfloat[0], pfloat[1], pfloat[2]);
				pt = (orient * (pt * scale)) + position;
				vertices[vct++] = pt.x;
				vertices[vct++] = pt.y;
				vertices[vct++] = pt.z;
			}

			vbuf->unlock();

			// normals
			const Ogre::VertexElement* nrmElem =
				vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL);

			Ogre::HardwareVertexBufferSharedPtr vbuf2 =
			vertex_data->vertexBufferBinding->getBuffer(nrmElem->getSource());

			unsigned char* vertex2 =
			static_cast<unsigned char*>(vbuf2->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));

			float* pfloat2;

			for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex2 += vbuf2->getVertexSize())
			{
				nrmElem->baseVertexPointerToElement(vertex, &pfloat2);
				Ogre::Vector3 pt(pfloat[0], pfloat[1], pfloat[2]);
				normals[nct++] = pt.x;
				normals[nct++] = pt.y;
				normals[nct++] = pt.z;
			}

			vbuf2->unlock();
			//

			next_offset += vertex_data->vertexCount;
		}

		//indices
		Ogre::IndexData* index_data = submesh->indexData;
		size_t numTris = index_data->indexCount / 3;
		Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
		bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
		unsigned int*  pLong = static_cast<unsigned int*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
		unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
		size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;
		if ( use32bitindexes )
		{
			for ( size_t k = 0; k < numTris*3; ++k)
			{
				indices[index_offset++] = pLong[k] + static_cast<unsigned int>(offset);
			}
		}
		else
		{
			for ( size_t k = 0; k < numTris*3; ++k)
			{
				unsigned int t = static_cast<unsigned int>(pShort[k]) + static_cast<unsigned int>(offset);
				indices[index_offset++] = static_cast<unsigned int>(pShort[k]) + static_cast<unsigned int>(offset);
			}
		}
		ibuf->unlock();
		current_offset = next_offset;

		//add material
		NxMaterialIndex mat = PHY->addNewMaterial(mat_name);
		int tri_count = numTris;
		
		for (int j=0;j<tri_count;j++)
		{
			materials[mct++] = mat;
		}
		
	}

	printf(">>>>>>> verts : %i / %i\n", vct, vertex_count);
	printf(">>>>>>> indexes : %i / %i\n", index_offset, index_count);
	printf(">>>>>>> normals : %i / %i\n", nct, index_count/3*3);
	printf(">>>>>>> mats : %i / %i\n", mct, index_count/3);
}